#include "phlogger.h"
#include "ProcessInfo.h"
#include "PHLogUser.h"
#include <string>
#include <sstream>
#include "..\phshared\phshared.h"
#include "boost/date_time/local_time_adjustor.hpp"
#include "boost/date_time/c_local_time_adjustor.hpp"
#include "boost/algorithm/string.hpp"
#include <set>
#include "..\phshared\Crc32Static.h"
#include "..\background\phacker.h" 

using namespace boost::posix_time;
using namespace boost::gregorian;
using namespace std;
using namespace boost;

extern CPHLogger logger;
extern map<string,long> PHPaths;
set<int> already_stopped_set;
vector<int> already_stopped;
vector<int> missing_executable;

 mutex as_mutex;
 extern mutex db_mutex;

/*Find out the user name and start time*/
CProcessInfo::CProcessInfo(long lPId)
{
	//_is_already_logged=false;
	_PId=lPId;
	_bValid=true;
	_UserID=-1;
	
	/*Win32 Start*/
	FILETIME ftCreation,ftExit,ftKernel,ftUser;

	HANDLE hProcess = OpenProcess(
			PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
			FALSE, lPId);
	
	if(hProcess==NULL)
	{
		PHMessage("Unable to open process handle "+ lexical_cast<string>(lPId));
		_bValid=false;
		return;
	}
	/*Retreive the process start time*/
	BOOL bRet = GetProcessTimes(hProcess,&ftCreation,&ftExit,&ftKernel,&ftUser);
	GetProcessUser(hProcess,_User);	
	
	wstringstream wss;
	
	PWSTR pCL= PHiGetCommandLine(hProcess);
	if(pCL!=0)
	{
		wss<<pCL;
	_commandline=wss.str();
	}
	PWSTR pPath = PHackGetImageFile(hProcess);
	if(pPath!=0)
	{
		wss.clear();
		wss<<pPath;
		//TODO WIDE _path=wss.str();
	}
	// PhaDereferenceObject(pCL);

	CloseHandle(hProcess);	


	if(bRet>0)
	{
		_WIN32Time=ftCreation;
	}
	else
	{
		Win32Error();//
		PHMessage("Unable to get Process Times");
		_bValid=false;
		return;
	}
	
	_UserID=GetUserID(_User);
	
	if(_UserID==-1)
		_bValid=false;
}

void CProcessInfo::ConvertStartTime()
{
	_StartTime=from_ftime<ptime>(_WIN32Time);
	/*store as local time*/
	_StartTime=date_time::c_local_adjustor<ptime>::utc_to_local(_StartTime);
}

/*Are the time, PID, user valid*/
bool CProcessInfo::Validate()	{	return _bValid;	}

/*The path to this  processes' module*/
void CProcessInfo::GetExecutableImage(bool first)//string & path)
{
	int i=0;
	string path;
	GetExecutableName(_PId,path);		/*END: TIME CRITICAL*/
	/*while(path.empty() && i<21)
	{
		Sleep(1000);
		{
			mutex::scoped_lock assl(as_mutex);
			if(already_stopped_set.find(_PId)!=already_stopped_set.end())
			{
				PHMessage("Already stopped: "+lexical_cast<string>(_PId));
				break;
			}
		}
		PHMessage("Retrying getexecutablename " + lexical_cast<string>(_PId));
		GetExecutableName(_PId,path);
		i++;
	}*/
	//missing_executable=false;
	if(path.empty())
	{
		PHMessage("Failed processinfo get executable image "+ lexical_cast<string>(_PId));
		//_bValid=false;
		if(first)
		missing_executable.insert(_PId);
		return;
	}
	else
	{
		replace_first(path,"\\??\\","");
			if(find_first(path,"SystemRoot"))
			{
				char*sysroot=getenv("SYSTEMROOT");
				replace_first(path,"\\SystemRoot",sysroot);
			}
		_path=path;
		//cout<<"path: "<<_path<<endl;
	}
	/*{
			mutex::scoped_lock assl(as_mutex);
			if(already_stopped_set.find(_PId)!=already_stopped_set.end())
			{
				PHMessage("Already stopped: "+lexical_cast<string>(_PId));
			}
			else
				WMIGetProcess(_PId,_commandline,"CommandLine","Win32_Process");
		}*/
	//WMIGetProcess(_PId,_commandline,"CommandLine","Win32_Process");
	
	DWORD dwCRC;
#if defined (_WIN64)
	CCrc32Static::FileCrc32Win32(_path.c_str(),dwCRC);
#else
	CCrc32Static::FileCrc32Assembly(_path.c_str(),dwCRC);
#endif
		_CRC=dwCRC;
	}


	
//map<string,long> PHCLs;
extern long getclid(wstring cl);

/*Log the process starting*/
void CProcessInfo::SaveProcess(ptime ExitTime)
{	
	ostringstream clSQL;
	
	long PathID=GetPathID(_path);
	if(PathID==-1)
		return;

	clSQL<<"INSERT INTO Process(CreationTime,PathID,CLID,UserID,CRC,Destruction) VALUES (JULIANDAY('" 	<< GetStartTime()
	<<"'),"	<<PathID;
	
	long CLID=getclid(_commandline);
	if(CLID==-1)
		return;
	clSQL<<","<<CLID;
	clSQL<<","<<_UserID;
	clSQL<<","<<_CRC;
	clSQL<<","<<"JULIANDAY('"	<<	BoostToSQLite(ExitTime);
	clSQL<<"');";
	
	
	sqlite3 * db;
	db=OpenDB();
	char * szErr;
	{
	mutex::scoped_lock lock(db_mutex);
	if(SQLITE_OK!=sqlite3_exec(db,clSQL.str().c_str(),NULL,NULL,&szErr))
		DBError(szErr,__LINE__,__FILE__);
	else 
		_ProcessID=sqlite3_last_insert_rowid(db);
	}
	if(_ProcessID<1)
		PHTrace("ProcessID less than 1",__LINE__,__FILE__);			
	
	sqlite3_close(db);
	
	return;
}

//void CProcessInfo::StartEvent()
//{
	/*Record this process, this will be the first time it has been 
	found in this instance.*/
	//SaveProcess();	
//}

